package org.atoum.intellij.plugin.atoum.run; import com.intellij.execution.ExecutionException; import com.intellij.execution.Executor; import com.intellij.execution.configurations.ConfigurationFactory; import com.intellij.execution.configurations.GeneralCommandLine; import com.intellij.execution.configurations.RunConfiguration; import com.intellij.execution.executors.DefaultRunExecutor; import com.intellij.execution.process.*; import com.intellij.execution.testframework.TestConsoleProperties; import com.intellij.execution.testframework.TestFrameworkRunningModel; import com.intellij.execution.testframework.sm.SMTestRunnerConnectionUtil; import com.intellij.execution.testframework.sm.runner.SMTRunnerConsoleProperties; import com.intellij.execution.testframework.sm.runner.SMTestProxy; import com.intellij.execution.testframework.sm.runner.ui.SMTRunnerConsoleView; import com.intellij.execution.testframework.sm.runner.ui.TestResultsViewer; import com.intellij.execution.testframework.ui.BaseTestsOutputConsoleView; import com.intellij.notification.Notification; import com.intellij.notification.NotificationType; import com.intellij.notification.Notifications; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.Key; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.wm.ToolWindow; import com.intellij.openapi.wm.ToolWindowAnchor; import com.intellij.openapi.wm.ToolWindowManager; import com.intellij.psi.PsiDirectory; import com.intellij.ui.content.Content; import com.intellij.ui.content.ContentManager; import com.jetbrains.php.config.PhpProjectConfigurationFacade; import com.jetbrains.php.config.interpreters.PhpConfigurationOptionData; import com.jetbrains.php.config.interpreters.PhpInterpreter; import com.jetbrains.php.run.PhpRunConfiguration; import com.jetbrains.php.run.PhpRunConfigurationFactoryBase; import org.atoum.intellij.plugin.atoum.AtoumUtils; import org.atoum.intellij.plugin.atoum.model.*; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.atoum.intellij.plugin.atoum.Icons; import java.io.File; import java.util.*; public class Runner { protected Project project; public Runner(Project project) { this.project = project; } public void run(RunnerConfiguration runnerConfiguration) { ToolWindow toolWindow = getToolWindow(); getConsole(toolWindow, project, runnerConfiguration); } public ToolWindow getToolWindow() { ToolWindow toolWindow; String windowId = "atoum"; if (!Arrays.asList(ToolWindowManager.getInstance(project).getToolWindowIds()).contains(windowId)) { toolWindow = ToolWindowManager.getInstance(project).registerToolWindow(windowId, false, ToolWindowAnchor.BOTTOM); } else { toolWindow = ToolWindowManager.getInstance(project).getToolWindow(windowId); } toolWindow.setIcon(Icons.ATOUM); toolWindow.show(null); return toolWindow; } // like // https://github.com/JetBrains/intellij-community/blob/6555e34dc0b5c4bd3a8c9efc7d8e5ca84929af40/platform/platform-impl/src/com/intellij/execution/process/ScriptRunnerUtil.java // with not log and charset support // but with environment variables support protected OSProcessHandler prepareProcessHandler(@NotNull String exePath, @Nullable String workingDirectory, String[] parameters, @Nullable Map<String, String> environment) throws ExecutionException { GeneralCommandLine commandLine = new GeneralCommandLine(exePath); commandLine.addParameters(parameters); if (workingDirectory != null) { commandLine.setWorkDirectory(workingDirectory); } commandLine.withEnvironment(environment); return new ColoredProcessHandler(commandLine); } public BaseTestsOutputConsoleView getConsole(ToolWindow toolWindow, Project project, final RunnerConfiguration runnerConfiguration) { ConfigurationFactory myFactory = new PhpRunConfigurationFactoryBase(new AtoumLocalRunConfigurationType()) { public RunConfiguration createTemplateConfiguration(Project project) { return new AtoumLocalRunConfiguration(project, this, ""); } }; Executor executor = DefaultRunExecutor.getRunExecutorInstance(); PhpRunConfiguration runConfiguration = new AtoumLocalRunConfiguration(project, myFactory, "test"); TestConsoleProperties testConsoleProperties = new SMTRunnerConsoleProperties(runConfiguration, "atoum", executor); final BaseTestsOutputConsoleView testsOutputConsoleView = SMTestRunnerConnectionUtil.createConsole("atoumConsole", testConsoleProperties); Disposer.register(project, testsOutputConsoleView); VirtualFile testBaseDir = null; try { testBaseDir = AtoumUtils.findTestBaseDir(runnerConfiguration, project); } catch (Exception e) { testBaseDir = project.getBaseDir(); } String testBasePath = testBaseDir.getPath(); String atoumBinPath = AtoumUtils.findAtoumBinPath(testBaseDir); String phpPath = "php"; PhpInterpreter interpreter = PhpProjectConfigurationFacade.getInstance(project).getInterpreter(); if (null != interpreter) { phpPath = interpreter.getPathToPhpExecutable(); } List<PhpConfigurationOptionData> phpConfig; try { phpConfig = interpreter.getConfigurationOptions(); } catch (NullPointerException e) { phpConfig = new ArrayList<PhpConfigurationOptionData>(); } CommandLineArgumentsBuilder commandLineBuilder = (new CommandLineArgumentsBuilder(atoumBinPath, testBasePath, phpConfig)) .useTapReport() .useConfiguration(runnerConfiguration) ; String phpstormConfigFile = testBasePath + "/.atoum.phpstorm.php"; if (new File(phpstormConfigFile).exists()) { commandLineBuilder.useConfigFile(phpstormConfigFile); } ContentManager contentManager = toolWindow.getContentManager(); Content myContent; myContent = toolWindow.getContentManager().getFactory().createContent(testsOutputConsoleView.getComponent(), "tests results", false); toolWindow.getContentManager().removeAllContents(true); toolWindow.getContentManager().addContent(myContent); final SMTRunnerConsoleView console = (SMTRunnerConsoleView)testsOutputConsoleView; String[] commandLineArgs = commandLineBuilder.build(); HashMap environnmentVariables = new HashMap(); environnmentVariables.put("PHPSTORM", "1"); OSProcessHandler processHandler = null; try { processHandler = this.prepareProcessHandler( phpPath, testBasePath, commandLineArgs, environnmentVariables ); testsOutputConsoleView.attachToProcess(processHandler); console.getResultsViewer().setAutoscrolls(true); TestConsoleProperties.HIDE_PASSED_TESTS.set(testsOutputConsoleView.getProperties(), true); TestConsoleProperties.SELECT_FIRST_DEFECT.set(testsOutputConsoleView.getProperties(), true); final OSProcessHandler finalProcessHandler = processHandler; console.getResultsViewer().addEventsListener(new TestResultsViewer.EventsListener() { final StringBuilder outputBuilder = new StringBuilder(); @Override public void onTestingStarted(TestResultsViewer testResultsViewer) { if (finalProcessHandler != null) { finalProcessHandler.addProcessListener(new ProcessAdapter() { public void onTextAvailable(ProcessEvent event, Key outputType) { outputBuilder.append(event.getText()); } public void processTerminated(ProcessEvent event) { } }); } } @Override public void onTestingFinished(TestResultsViewer testResultsViewer) { SMTestProxy testsRootNode = testResultsViewer.getTestsRootNode(); if (outputBuilder.length() == 0) { testsRootNode.setTestFailed("No tests were found!", "", true); return; } TestsResult testsResult = TestsResultFactory.createFromTapOutput(outputBuilder.toString()); SMTRootTestProxyFactory.updateFromTestResult(testsResult, testsRootNode); selectFirstFailedMethod(); if (testsResult.getState().equals(testsResult.STATE_PASSED)) { TestConsoleProperties.HIDE_PASSED_TESTS.set(testsOutputConsoleView.getProperties(), false); } } protected void selectFirstFailedMethod() { for (SMTestProxy testProxy: console.getResultsViewer().getTestsRootNode().getAllTests()) { for (SMTestProxy methodProxy: testProxy.getAllTests()) { if (methodProxy.isDefect()) { console.getResultsViewer().selectAndNotify(methodProxy); } } } } @Override public void onTestNodeAdded(TestResultsViewer testResultsViewer, SMTestProxy smTestProxy) { } @Override public void onSelected(@Nullable SMTestProxy smTestProxy, @NotNull TestResultsViewer testResultsViewer, @NotNull TestFrameworkRunningModel testFrameworkRunningModel) { } }); processHandler.startNotify(); } catch (ExecutionException e) { Notifications.Bus.notify(new Notification("atoumGroup", "Error running tests", e.getMessage(), NotificationType.ERROR, null), project); } return testsOutputConsoleView; } }